import { EntityInfo, AddressProfile, AddressAssociation, ChainType } from '../../types';
import { createModuleLogger } from '../../utils/logger';
import { DatabaseService } from '../database/DatabaseService';

const logger = createModuleLogger('entity-clustering');

export class EntityClusteringService {
  private static instance: EntityClusteringService;
  private dbService: DatabaseService;
  private clusteringCache = new Map<string, EntityInfo>();
  private associationCache = new Map<string, AddressAssociation[]>();

  private constructor(dbService: DatabaseService) {
    this.dbService = dbService;
  }

  public static getInstance(dbService: DatabaseService): EntityClusteringService {
    if (!EntityClusteringService.instance) {
      EntityClusteringService.instance = new EntityClusteringService(dbService);
    }
    return EntityClusteringService.instance;
  }

  /**
   * Analyze address relationships and perform entity clustering
   */
  public async analyzeAddressCluster(address: string, chain: ChainType): Promise<EntityInfo | null> {
    try {
      const cacheKey = `${address.toLowerCase()}_${chain}`;
      
      // Check cache
      if (this.clusteringCache.has(cacheKey)) {
        return this.clusteringCache.get(cacheKey) || null;
      }

      logger.info(`Starting address entity clustering analysis: ${address} on ${chain}`);

      // Get address transaction history
      const transactions = await this.dbService.getTransactionsByAddress(address, chain);
      if (transactions.length < 3) {
        logger.debug(`Address ${address} has insufficient transaction records, skipping clustering analysis`);
        return null;
      }

      // Analyze funding relationships
      const fundingRelations = await this.analyzeFundingRelations(address, chain, transactions);
      
      // Analyze behavioral pattern similarity
      const behaviorRelations = await this.analyzeBehaviorSimilarity(address, chain, transactions);

      // Merge all relationships
      const allRelations = [...fundingRelations, ...behaviorRelations];
      
      if (allRelations.length === 0) {
        return null;
      }

      // Create or get entity information
      const entity = await this.createOrUpdateEntity(address, chain, allRelations);
      
      // Cache result
      this.clusteringCache.set(cacheKey, entity);
      
      logger.info(`Entity clustering completed: ${entity.name}, contains ${entity.addresses.length} addresses`);
      return entity;

    } catch (error) {
      logger.error(`Address clustering analysis failed ${address}:`, error);
      return null;
    }
  }

  /**
   * 分析资金流关联关系
   */
  private async analyzeFundingRelations(
    address: string, 
    chain: ChainType, 
    transactions: any[]
  ): Promise<AddressAssociation[]> {
    const relations: AddressAssociation[] = [];
    const addressInteractions = new Map<string, { count: number, totalAmount: number, firstSeen: Date }>();

    // 统计与其他地址的交互频率和金额
    for (const tx of transactions) {
      const relatedAddress = tx.from === address ? tx.to : tx.from;
      if (!relatedAddress || relatedAddress === address) continue;

      const key = relatedAddress.toLowerCase();
      const existing = addressInteractions.get(key);
      
      if (existing) {
        existing.count++;
        existing.totalAmount += tx.valueUSD;
        if (tx.timestamp < existing.firstSeen) {
          existing.firstSeen = tx.timestamp;
        }
      } else {
        addressInteractions.set(key, {
          count: 1,
          totalAmount: tx.valueUSD,
          firstSeen: tx.timestamp
        });
      }
    }

    // 分析高频交互地址
    for (const [relatedAddress, data] of addressInteractions) {
      if (data.count >= 3 && data.totalAmount > 10000) { // 至少3次交易且总额超过1万美元
        const strength = this.calculateRelationStrength(data.count, data.totalAmount, transactions.length);
        
        if (strength > 0.3) { // 关联强度阈值
          relations.push({
            relatedAddress,
            relationshipType: 'funding',
            strength,
            evidence: [
              `${data.count}次交易`,
              `总金额: $${data.totalAmount.toLocaleString()}`,
              `首次交互: ${data.firstSeen.toDateString()}`
            ],
            firstSeen: data.firstSeen
          });
        }
      }
    }

    return relations;
  }

  /**
   * 分析行为模式相似性
   */
  private async analyzeBehaviorSimilarity(
    address: string, 
    chain: ChainType, 
    transactions: any[]
  ): Promise<AddressAssociation[]> {
    const relations: AddressAssociation[] = [];

    // 分析交易时间模式
    const timePattern = this.extractTimePattern(transactions);
    
    // 分析交易金额模式
    const amountPattern = this.extractAmountPattern(transactions);

    // 查找具有相似模式的地址
    const similarAddresses = await this.findSimilarPatternAddresses(
      chain, 
      timePattern, 
      amountPattern
    );

    for (const similarAddr of similarAddresses) {
      relations.push({
        relatedAddress: similarAddr.address,
        relationshipType: 'similar_pattern',
        strength: similarAddr.similarity,
        evidence: [
          `时间模式相似度: ${(similarAddr.timeSimilarity * 100).toFixed(1)}%`,
          `金额模式相似度: ${(similarAddr.amountSimilarity * 100).toFixed(1)}%`
        ],
        firstSeen: new Date()
      });
    }

    return relations;
  }

  /**
   * 计算关联强度
   */
  private calculateRelationStrength(
    transactionCount: number, 
    totalAmount: number, 
    totalTransactions: number
  ): number {
    const frequencyScore = Math.min(transactionCount / totalTransactions, 0.5);
    const amountScore = Math.min(Math.log10(totalAmount) / 6, 0.5); // log scale for amount
    return frequencyScore + amountScore;
  }

  /**
   * 提取时间模式
   */
  private extractTimePattern(transactions: any[]): any {
    const hours = transactions.map(tx => new Date(tx.timestamp).getHours());
    const days = transactions.map(tx => new Date(tx.timestamp).getDay());
    
    return {
      preferredHours: this.findFrequentValues(hours),
      preferredDays: this.findFrequentValues(days),
      regularity: this.calculateRegularity(transactions.map(tx => tx.timestamp))
    };
  }

  /**
   * 提取金额模式
   */
  private extractAmountPattern(transactions: any[]): any {
    const amounts = transactions.map(tx => tx.valueUSD);
    amounts.sort((a, b) => a - b);

    return {
      medianAmount: amounts[Math.floor(amounts.length / 2)],
      avgAmount: amounts.reduce((sum, amt) => sum + amt, 0) / amounts.length,
      amountVariation: this.calculateVariation(amounts),
      frequentAmounts: this.findFrequentAmountRanges(amounts)
    };
  }

  /**
   * 查找频繁值
   */
  private findFrequentValues(values: number[]): number[] {
    const frequency = new Map<number, number>();
    values.forEach(val => {
      frequency.set(val, (frequency.get(val) || 0) + 1);
    });

    const threshold = values.length * 0.2; // 20%以上的频率
    return Array.from(frequency.entries())
      .filter(([_, count]) => count > threshold)
      .map(([value, _]) => value);
  }

  /**
   * 计算规律性
   */
  private calculateRegularity(timestamps: Date[]): number {
    if (timestamps.length < 3) return 0;

    const intervals = [];
    for (let i = 1; i < timestamps.length; i++) {
      intervals.push(timestamps[i].getTime() - timestamps[i-1].getTime());
    }

    const avgInterval = intervals.reduce((sum, interval) => sum + interval, 0) / intervals.length;
    const variance = intervals.reduce((sum, interval) => sum + Math.pow(interval - avgInterval, 2), 0) / intervals.length;
    
    // 规律性 = 1 - 标准差/平均值 (归一化)
    return Math.max(0, 1 - Math.sqrt(variance) / avgInterval);
  }

  /**
   * 计算变异度
   */
  private calculateVariation(amounts: number[]): number {
    const avg = amounts.reduce((sum, amt) => sum + amt, 0) / amounts.length;
    const variance = amounts.reduce((sum, amt) => sum + Math.pow(amt - avg, 2), 0) / amounts.length;
    return Math.sqrt(variance) / avg; // 变异系数
  }

  /**
   * 查找频繁金额范围
   */
  private findFrequentAmountRanges(amounts: number[]): Array<{min: number, max: number, count: number}> {
    const ranges: Array<{min: number, max: number, count: number}> = [];
    const buckets = 10; // 分成10个桶
    const min = Math.min(...amounts);
    const max = Math.max(...amounts);
    const bucketSize = (max - min) / buckets;

    for (let i = 0; i < buckets; i++) {
      const rangeMin = min + i * bucketSize;
      const rangeMax = min + (i + 1) * bucketSize;
      const count = amounts.filter(amt => amt >= rangeMin && amt < rangeMax).length;
      
      if (count > amounts.length * 0.1) { // 超过10%的交易在此范围
        ranges.push({ min: rangeMin, max: rangeMax, count });
      }
    }

    return ranges;
  }

  /**
   * 查找相似模式的地址
   */
  private async findSimilarPatternAddresses(
    chain: ChainType,
    timePattern: any,
    amountPattern: any
  ): Promise<Array<{address: string, similarity: number, timeSimilarity: number, amountSimilarity: number}>> {
    // 这里应该查询数据库中的其他地址模式
    // 简化实现，返回空数组
    return [];
  }

  /**
   * 创建或更新实体
   */
  private async createOrUpdateEntity(
    address: string,
    chain: ChainType,
    relations: AddressAssociation[]
  ): Promise<EntityInfo> {
    // 检查是否已存在实体
    const existingEntity = await this.findExistingEntity(address, chain);
    
    if (existingEntity) {
      // 更新现有实体
      const updatedAddresses = [...new Set([...existingEntity.addresses, address])];
      const updatedChains = [...new Set([...existingEntity.chains, chain])];
      
      const updatedEntity: EntityInfo = {
        ...existingEntity,
        addresses: updatedAddresses,
        chains: updatedChains,
        lastUpdated: new Date()
      };

      await this.saveEntity(updatedEntity);
      return updatedEntity;
    } else {
      // 创建新实体
      const newEntity: EntityInfo = {
        id: `entity_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
        name: this.generateEntityName(address, relations),
        type: this.determineEntityType(relations),
        addresses: [address],
        chains: [chain],
        riskScore: this.calculateRiskScore(relations),
        confidence: this.calculateConfidence(relations),
        lastUpdated: new Date(),
        metadata: {
          discoveredBy: 'clustering_analysis',
          relationCount: relations.length
        }
      };

      await this.saveEntity(newEntity);
      return newEntity;
    }
  }

  /**
   * 查找现有实体
   */
  private async findExistingEntity(address: string, chain: ChainType): Promise<EntityInfo | null> {
    // 这里应该查询数据库
    // 简化实现
    return null;
  }

  /**
   * 生成实体名称
   */
  private generateEntityName(address: string, relations: AddressAssociation[]): string {
    const hasExchangeRelation = relations.some(r => r.relationshipType === 'funding');
    const shortAddr = `${address.substring(0, 6)}...${address.substring(address.length - 4)}`;
    
    if (hasExchangeRelation) {
      return `实体 ${shortAddr} (资金关联)`;
    } else {
      return `实体 ${shortAddr} (模式关联)`;
    }
  }

  /**
   * 确定实体类型
   */
  private determineEntityType(relations: AddressAssociation[]): EntityInfo['type'] {
    const fundingRelations = relations.filter(r => r.relationshipType === 'funding');
    
    if (fundingRelations.length > 3) {
      return 'institution';
    } else if (fundingRelations.length > 0) {
      return 'individual';
    } else {
      return 'unknown';
    }
  }

  /**
   * 计算风险评分
   */
  private calculateRiskScore(relations: AddressAssociation[]): number {
    let riskScore = 20; // 基础风险分

    // 根据关联数量增加风险
    riskScore += relations.length * 5;

    // 根据关联强度增加风险
    const avgStrength = relations.reduce((sum, r) => sum + r.strength, 0) / relations.length;
    riskScore += avgStrength * 30;

    return Math.min(100, Math.max(0, riskScore));
  }

  /**
   * 计算置信度
   */
  private calculateConfidence(relations: AddressAssociation[]): number {
    if (relations.length === 0) return 0;
    
    const avgStrength = relations.reduce((sum, r) => sum + r.strength, 0) / relations.length;
    const relationCount = Math.min(relations.length / 10, 1); // 最多10个关联达到满分
    
    return (avgStrength * 0.7 + relationCount * 0.3);
  }

  /**
   * 保存实体信息
   */
  private async saveEntity(entity: EntityInfo): Promise<void> {
    // 这里应该保存到数据库
    logger.info(`保存实体信息: ${entity.name}`);
  }

  /**
   * 获取实体关系图数据
   */
  public async getEntityGraph(entityId: string): Promise<{nodes: any[], edges: any[]}> {
    // 这里应该查询数据库获取实体的完整关系图
    return { nodes: [], edges: [] };
  }

  /**
   * 清理过期缓存
   */
  public clearExpiredCache(): void {
    if (this.clusteringCache.size > 500) {
      this.clusteringCache.clear();
      this.associationCache.clear();
      logger.debug('已清理实体聚类缓存');
    }
  }
} 